﻿using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;

using System.Runtime.InteropServices;
using SF.Code.Extension.WinAPI;

namespace SG.Sys.MouseHook
{
    public partial class Form1 : Form
    {
        //Declare MouseHookProcedure as a HookProc type.
        User32.HookProc _mouseHookProcedure;
        //Declare the hook handle as an int.
        static int _hHook = 0;

        public Form1()
        {
            InitializeComponent();
        }

        public static int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            //Marshall the data from the callback.
            var hookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

            if (nCode < 0)
            {
                return User32.CallNextHookEx(_hHook, nCode, wParam, lParam);
            }
            //Create a string variable that shows the current mouse coordinates.
            var strCaption =
                string.Format("wParam = {5:x} x = {0:d} y = {1:d} hwnd = {2:x} testCode = {3:x} extra = {4:x}",
                              hookStruct.pt.x, hookStruct.pt.y, hookStruct.hwnd, hookStruct.wHitTestCode,
                              hookStruct.dwExtraInfo.ToInt64(), wParam.ToInt64());
            //You must get the active form because it is a static function.
            var tempForm = ActiveForm;

            //Set the caption of the form.
            if (tempForm != null) tempForm.Text = strCaption;
            return User32.CallNextHookEx(_hHook, nCode, wParam, lParam);
        }

        public static int MouseLLHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            //Marshall the data from the callback.
            var hookStruct = (MouseLowLevelHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLowLevelHookStruct));

            if (nCode < 0)
            {
                return User32.CallNextHookEx(_hHook, nCode, wParam, lParam);
            }
            //Create a string variable that shows the current mouse coordinates.
            var strCaption =
                string.Format(
                    "wParam = {6:x} x = {0:d} y = {1:d} flags = {2:x} mouseData = {3:x} extra = {4:x} time = {5:x}",
                    hookStruct.pt.x, hookStruct.pt.y, hookStruct.flags, hookStruct.mouseData,
                    hookStruct.dwExtraInfo.ToInt64(), hookStruct.time, wParam.ToInt64());
            //You must get the active form because it is a static function.
            var tempForm = ActiveForm;

            //Set the caption of the form.
            if (tempForm != null) tempForm.Text = strCaption;
            return User32.CallNextHookEx(_hHook, nCode, wParam, lParam);
        }

        

        private void button1_Click(object sender, EventArgs e)
        {

            if (_hHook == 0)
            {
                // Create an instance of HookProc.
                _mouseHookProcedure = MouseLLHookProc;

                /*
                _hHook = User32.SetWindowsHookEx(WindowHook.WH_MOUSE,
                            _mouseHookProcedure,
                            IntPtr.Zero,
                            AppDomain.GetCurrentThreadId());
                 * 
                */
                using (var curProcess = Process.GetCurrentProcess())
                using (var curModule = curProcess.MainModule)
                {
                    _hHook = User32.SetWindowsHookEx(HookType.WH_MOUSE_LL,
                                                     _mouseHookProcedure,
                                                     Kernel32.GetModuleHandle(curModule.ModuleName), 0);
                }

                //If the SetWindowsHookEx function fails.
                if (_hHook == 0)
                {
                    MessageBox.Show("SetWindowsHookEx Failed");
                    return;
                }
                button1.Text = "UnHook Windows Hook";
            }
            else
            {
                bool ret = User32.UnhookWindowsHookEx(_hHook);
                //If the UnhookWindowsHookEx function fails.
                if (ret == false)
                {
                    MessageBox.Show("UnhookWindowsHookEx Failed");
                    return;
                }
                _hHook = 0;
                button1.Text = "Set Windows Hook";
                this.Text = "Mouse Hook";
            } 
        }
    }
}
